import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 多线程实现复制文件夹
 *
 * @Author Azer
 * @LOVE,,,
 * @Date 2021/9/26 20:33
 */

public class ThreadPoolCopyFile {
    public static void main(String[] args) {
        //设置目标文件夹
        String destPath = "F:\\heima";

        //获取要复制文件夹下的所有文件
        Map<String, String> map = getFiles("D:\\test", new HashMap<String, String>(), destPath);

        //map集合中存储的就是：源文件目录下的所有文件路径（包含子文件，子目录）

        //创建线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(3);

        //遍历集合
        Set<String> keySet = map.keySet();
        for (String key : keySet) {

            //执行线程任务（使用线程执行任务后（子线程），由CPU来控制）
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    //实现文件复制，把文件从源文件中读出来，再写进目标文件中
                    FileInputStream fileInputStream = null;
                    FileOutputStream fileOutputStream = null;


                    try {
                        //要复制的源文件，创建一个字节输入流与源文件接通
                        File originFile = new File(key);
                        fileInputStream = new FileInputStream(originFile);

                        //复制的目标文件
                        String destPath = map.get(key);
                        File destFile = new File(destPath);

                        //如果目标文件不存在则创建
                        if(!destFile.exists()){
                            destFile.mkdirs();
                        }

                        //创建一个字节输出流与目标文件接通
                        fileOutputStream=new FileOutputStream(destFile+File.separator
                        +originFile.getName());

                        //利用一个字节数组，把数据读进去
                        byte [] b=new byte[1024];
                        int len;//记录每次读取的字节数
                        while ((len=fileInputStream.read(b))!=-1){
                            //读多少写多少
                            fileOutputStream.write(b,0,len);
                            //刷新字节输出流
                            fileOutputStream.flush();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        //关闭字节输入流
                        if(fileInputStream!=null){
                            try {
                                fileInputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                        //关闭字节输出流
                        if(fileOutputStream!=null){
                            try {
                                fileOutputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            });
        }
        //关闭线程池
        threadPool.shutdown();

        System.out.println("复制完成！");
    }

    /**
     * 穿件一个复制文件夹的方法
     * 获取文件夹下的所有文件
     * 存储所有文件map(源文件地址，目标文件夹)
     * 复制到目标文件夹下
     *
     * @param dir  源文件
     * @param map
     * @param dest 目标文件夹（复制后要存放的地方）
     * @return
     */
    public static Map<String, String> getFiles(String dir, Map<String, String> map, String dest) {
        if (dir == null || "".equals(dir)) {//文件夹名称不能为空
            return map;
        } else {
            //开始对文件夹进行逐个遍历，逐个复制
            File file = new File(dir);
            if (file.isDirectory()) {//判断是否是文件夹

                //是文件夹
                //获取当前文件夹下的所有文件
                File[] files = file.listFiles();

                //判断当前文件夹里是否存在文件
                if (files != null && files.length > 0) {

                    //文件夹里有东西
                    //遍历文件夹里面的东西（文件）
                    for (File fileSub : files) {
                        //获取每个文件的绝对路径
                        String filePath = fileSub.getAbsolutePath();
                        //获取每个文件的名字
                        String fileName = fileSub.getName();

                        //如果找到的是文件；就直接将文件路径，文件名存入到map集合中
                        if (fileSub.isFile()) {
                            getFiles(filePath, map, dest);
                        } else {//如果找到的是文件夹，继续递归获取里面的文件
                            //File.separator 相当于"\"
                            getFiles(filePath, map, dest + File.separator + fileName);

                        }
                    }
                }
            } else {//是文件直接存入集合
                map.put(dir, dest);

            }
        }

        return map;

    }

}
